/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
 *
 */

import fse from 'fs-extra';
import path from 'path';

import { CommonConst } from '../../const/common-const';
import { ohPackageLoader } from '../loader/file/oh-package-loader';
import { OhosLogger } from '../log/ohos-logger.js';

import { ResolverCache } from './resolver-cache.js';

const ROOT_PATH_REGEX = /^([A-Za-z]:)?[\\/]+/;

export class BasePackageResolver {
  private readonly packageFileWord: string;
  private readonly moduleDirWord: string;

  constructor(packageFileWord: string, moduleDirWord: string) {
    this.packageFileWord = packageFileWord;
    this.moduleDirWord = moduleDirWord;
  }

  /**
   * 基于类node_modules的结构，向上寻找
   * @param {string} moduleName
   * @param {string} initDir
   * @returns {string | null}
   */
  resolvePackagePath(moduleName: string, initDir: string, log?: OhosLogger): string | undefined {
    // 该方法作用是将替换成.hvigor下的package.json的路径替换成原路径，否则无法根据目录结构找到对应的oh_modules下的依赖
    if (initDir.includes(CommonConst.DEPENDENCYMAP)) {
      if (ResolverCache.get(path.resolve(initDir))) {
        initDir = ResolverCache.get(path.resolve(initDir)) as string;
      } else {
        ohPackageLoader.OhPackagePathMap.forEach((newPath, oldPath) => {
          ResolverCache.set(path.dirname(newPath), path.dirname(oldPath));
        });
        initDir = ResolverCache.get(path.resolve(initDir)) || initDir;
      }
    }
    if (ResolverCache.has(`${moduleName}\x00${initDir}\x00${this.packageFileWord}`)) {
      return ResolverCache.get(`${moduleName}\x00${initDir}\x00${this.packageFileWord}`);
    }
    const absolutePath = path.resolve(initDir);
    const fsRoot = ROOT_PATH_REGEX.test(absolutePath) ? ROOT_PATH_REGEX.exec(absolutePath)![0] : path.resolve('/');
    let curPath = absolutePath;
    while (fsRoot !== curPath) {
      if (path.basename(curPath).toLowerCase() === this.moduleDirWord.toLowerCase()) {
        curPath = path.dirname(curPath);
      }
      const filePath = path.resolve(curPath, this.moduleDirWord, moduleName);
      if (fse.pathExistsSync(filePath)) {
        const realPath = path.resolve(fse.realpathSync.native(filePath), this.packageFileWord);
        ResolverCache.set(`${moduleName}\x00${initDir}\x00${this.packageFileWord}`, realPath);
        return realPath;
      } else {
        try {
          const stat = fse.lstatSync(filePath);
          stat.isSymbolicLink() && log?.warn('Please confirm the symbolic link is valid: ', filePath);
        } catch (e) {
          /* empty */
        }
        curPath = path.dirname(curPath);
      }
    }
    return undefined;
  }
}
